#include "main.h"
#include "ParsePMT.h"
#include "ParseType.h"
#include "ParseTS_Head.h"

int PmtStreamCount;
void TSPMTstream(unsigned char PMTtable[204], TS_PMT *NewPmtPoint);

void TSPMT_table(unsigned char PMTtable[204], TS_PMT *NewPmtPoint)
{
	int PMT_Length = 0;
    unsigned char descriptor[204] = {0};

	NewPmtPoint->table_id = PMTtable[0];
	NewPmtPoint->section_syntax_indicator = PMTtable[1] >> 7;
	NewPmtPoint->zero = (PMTtable[1] >> 6) & 0x01;
	NewPmtPoint->reserved_1 = (PMTtable[1] >> 4) & 0x03;
	NewPmtPoint->section_length = ((PMTtable[1] & 0x0F) << 8) | PMTtable[2];
	NewPmtPoint->program_number = (PMTtable[3] << 8) | PMTtable[4];
	NewPmtPoint->reserved_2 = PMTtable[5] >> 6;
	NewPmtPoint->version_number = (PMTtable[5] >> 1) & 0x1F;
	NewPmtPoint->current_next_indicator = (PMTtable[5] << 7) >> 7;
	NewPmtPoint->section_number = PMTtable[6];
	NewPmtPoint->last_section_number = PMTtable[7];
	NewPmtPoint->reserved_3 = PMTtable[8] >> 5;
	NewPmtPoint->PCR_PID = ((PMTtable[8] << 8) | PMTtable[9]) & 0x1FFF;
	NewPmtPoint->reserved_4 = PMTtable[10] >> 4;
	NewPmtPoint->program_info_length = ((PMTtable[10] & 0x0F) << 8) | PMTtable[11];

	if (0 != NewPmtPoint->program_info_length)
	{
		memcpy(NewPmtPoint->program_info_descriptor, PMTtable + 12, NewPmtPoint->program_info_length);
	}

	PMT_Length = NewPmtPoint->section_length + 3;
	NewPmtPoint->CRC_32 = (PMTtable[PMT_Length - 4] << 24) | (PMTtable[PMT_Length - 3] << 16)
	        | (PMTtable[PMT_Length - 2] << 8) | PMTtable[PMT_Length - 1];


    TSPMTstream(PMTtable,NewPmtPoint);
    
    NewPmtPoint->next = NULL;
    NewPmtPoint->Previous = PmtPoint;
    PmtPoint->next = NewPmtPoint;
    PmtPoint = PmtPoint->next;

}

void TSPMTstream(unsigned char PMTtable[204], TS_PMT *NewPmtPoint)
{
    int PmtStreamPosition = 12;
    PmtStreamCount = 0;
    int PMT_Length = NewPmtPoint->section_length + 3;


    for(PmtStreamPosition += NewPmtPoint->program_info_length; PmtStreamPosition < (PMT_Length - 4); PmtStreamPosition += 5)
    {

        NewPmtPoint->astPMT_Stream[PmtStreamCount].stream_type = PMTtable[PmtStreamPosition];
       
        NewPmtPoint->astPMT_Stream[PmtStreamCount].reserved_5 = (PMTtable[PmtStreamPosition + 1]) >> 5;
        NewPmtPoint->astPMT_Stream[PmtStreamCount].elementary_PID = ((PMTtable[PmtStreamPosition + 1] & 0x1f) << 8) 
                | PMTtable[PmtStreamPosition + 2];
        NewPmtPoint->astPMT_Stream[PmtStreamCount].reserved_6 = (PMTtable[PmtStreamPosition + 3] >> 4);
        NewPmtPoint->astPMT_Stream[PmtStreamCount].ES_info_length = ((PMTtable[PmtStreamPosition + 3] & 0xf) << 8)
                | PMTtable[PmtStreamPosition + 4];
        
        if(NewPmtPoint->astPMT_Stream[PmtStreamCount].ES_info_length != 0)
        {
            memcpy(NewPmtPoint->astPMT_Stream[PmtStreamCount].descriptor, PMTtable + PmtStreamPosition + 5,
			        NewPmtPoint->astPMT_Stream[PmtStreamCount].ES_info_length);
			PmtStreamPosition += NewPmtPoint->astPMT_Stream[PmtStreamCount].ES_info_length;
        }

        PmtStreamCount++;
    }

}

void ParseStreamType(PMT_INFO TS_Program, TS_PMT *NewPmtPoint)
{
    int ProgramPoint = 0;
    
    TS_Program.ProgramNumber = NewPmtPoint->program_number;

    for(int i = 0; i < PmtStreamCount; i++)
    {
        if((NewPmtPoint->astPMT_Stream[i].stream_type == 0x01)|| (NewPmtPoint->astPMT_Stream[i].stream_type == 0x02) 
                || (NewPmtPoint->astPMT_Stream[i].stream_type ==0x1b))
        {
            TS_Program.VideoPID = NewPmtPoint->astPMT_Stream[i].elementary_PID;
        }

        if((NewPmtPoint->astPMT_Stream[i].stream_type == 0x03)|| (NewPmtPoint->astPMT_Stream[i].stream_type == 0x04) 
                || (NewPmtPoint->astPMT_Stream[i].stream_type ==0x0f) || (NewPmtPoint->astPMT_Stream[i].stream_type == 0x11))
        {
            TS_Program.AudioPID[ProgramPoint] = NewPmtPoint->astPMT_Stream[i].elementary_PID;
            
            ProgramPoint++;
        }
    }

    printf("----------------------PMTINFO-----------------------\n");
    printf("ProgramNumber = %x\n",TS_Program.ProgramNumber);
    printf("VideoPID = %x\n",TS_Program.VideoPID);
    for (int p = 0; p < ProgramPoint; p++)
    {
        printf("AudioPID[%d] = %x\n",p,TS_Program.AudioPID[p]);
    }
    
}
 
void ParseTS_PMT(int TsPackage_len, TS_Package_Head TS_PackagePMTHead)
{
    unsigned char PMTtable[204] = {0};
    int PMT_Length = 0;
    TS_PMT TS_PackagePMT = {0};
    PMT_INFO TS_Program = {0};
    TS_PMT *NewPmtPoint = (TS_PMT *)malloc(sizeof(TS_PMT));
    
        if(TS_PackagePMTHead.payload_unit_start_indicator == 1)
        {
            memcpy(PMTtable, TSdata+5, TsPackage_len-5);
            
            TSPMT_table(PMTtable, NewPmtPoint);

            ParseStreamType(TS_Program, NewPmtPoint);
        }
       
}